//
// Created by hjie on 23-9-3.
//

#include "base_protocol.h"
#include "./msg_key.h"
#include "./../logic/message_router.h"
#include "util/rapidjson_util.h"

BaseProtocol::BaseProtocol()
{

}

void BaseProtocol::MakeResponseHeaderProtocol()
{
    m_response_header = std::make_shared<ResponseHeaderProtocol>();
}

void BaseProtocol::MakeResponseHeaderProtocol(const std::string &msg_type, const std::string &room_id, int policy, int result)
{
    m_response_header = std::make_shared<ResponseHeaderProtocol>();
    m_response_header->m_msg_type = msg_type;
    m_response_header->m_room_id  = room_id;
    m_response_header->m_policy   = policy;
    m_response_header->m_result   = result;
}

void BaseProtocol::CopyFromRequestHeader(std::shared_ptr<BaseProtocol> &dst)
{
    if (dst)
    {
        if (!dst->m_response_header)
        {
            dst->MakeResponseHeaderProtocol();
        }
        dst->m_response_header->m_user_id  = m_request_header->m_user_id;
        dst->m_response_header->m_msg_type = m_request_header->m_msg_type;
        dst->m_request_header->m_room_id   = m_request_header->m_room_id;
    }
}

void BaseProtocol::Dump(rapidjson::Document &output)
{
    hnhj::AddObjectMember(output, header_k);
    rapidjson::Value & header_value = output[header_k];
    if (m_response_header)
    {
        hnhj::AddStringMember(header_value, output.GetAllocator(), msg_type_k, m_response_header->m_msg_type);
        hnhj::AddStringMember(header_value, output.GetAllocator(), room_id_k, m_response_header->m_room_id);
        hnhj::AddIntMember(header_value, output.GetAllocator(), policy_k, m_response_header->m_policy);
        if (!m_response_header->m_user_id.empty())
        {
            hnhj::AddStringMember(header_value, output.GetAllocator(), user_id_k, m_response_header->m_user_id);
        }
        hnhj::AddIntMember(header_value, output.GetAllocator(), result_k, m_response_header->m_result);
        if (!m_response_header->m_from_user_id.empty())
        {
            hnhj::AddStringMember(header_value, output.GetAllocator(), from_k, m_response_header->m_from_user_id);
        }
        if (!m_response_header->m_to_user_id.empty())
        {
            hnhj::AddStringMember(header_value, output.GetAllocator(), to_k, m_response_header->m_to_user_id);
        }
    }
}

bool BaseProtocol::ParseData(rapidjson::Document &input)
{
    return true;
}

std::shared_ptr<BaseProtocol> BaseProtocol::ParseHeaderData(rapidjson::Document &input)
{
    // check header field
    if (input.HasMember(header_k) && input[header_k].IsObject())
    {
        rapidjson::Value & header = input[header_k];
        if (header.HasMember(user_id_k) && header[user_id_k].IsString() &&
            header.HasMember(msg_type_k) && header[msg_type_k].IsString() &&
            header.HasMember(room_id_k)  && header[room_id_k].IsString())
        {
            std::string msg_type = header[msg_type_k].GetString();
            auto router = MessageRouter::Instance();
            auto module = router->m_module_map.find(msg_type);
            if (module == router->m_module_map.end())
            {
                return nullptr;
            }
            auto protocol = module->second->CreateProtocolData(msg_type, input);
            if (protocol && input.HasMember(content_k) && input[content_k].IsObject())
            {
                bool parse_result = protocol->ParseData(input);
                if (parse_result)
                {
                    protocol->m_request_header = std::make_shared<RequestHeaderProtocol>();
                    protocol->m_request_header->m_msg_type = msg_type;
                    protocol->m_request_header->m_room_id  = header[room_id_k].GetString();
                    protocol->m_request_header->m_user_id  = header[user_id_k].GetString();
                }
                else
                {
                    return nullptr;
                }
                return protocol;
            }
            else
            {
                return nullptr;
            }
        }
        else
        {
            // check header data fail
            return nullptr;
        }
    }
    else
    {
        // no header field
        return nullptr;
    }
}